<template>
  <!-- 表格 -->
  <el-card class="box-card">
    <div class="search">
      <el-input v-if="isValueExists('user-getuserpage')" v-model="listQuery.searchString" placeholder="请输入关键字"
        style="width: 400px;" />
      <el-button v-if="isValueExists('user-getuserpage')" class="button" :icon="Search" type="primary"
        @click.prevent="userQuery">查询</el-button>
      <el-button v-if="isValueExists('user-adduser')" class="button" :icon="Plus" @click.prevent="addInfo">新增</el-button>
    </div>
    <el-table :data="tableData" stripe style="width: 100%">
      <el-table-column prop="avatarPath" label="头像">
        <template #default="{ row }">
          <el-image :preview-src-list="[imgUrlFilter(row.avatarPath)]" preview-teleported="true" v-if="row.avatarPath"
            :src="imgUrlFilter(row.avatarPath)" class="avatar" style="width: 50px; height: 50px;" />
        </template>
      </el-table-column>
      <el-table-column prop="userId" label="ID" />
      <el-table-column prop="name" label="姓名" />
      <el-table-column prop="sex" label="性别">
        <template #default="{ row }">
          <el-tag :type="row.sex == 0 ? '' : row.sex == 1 ? 'warning' : 'danger'">
            {{ sexFilter(row.sex) }}
          </el-tag>
        </template>
      </el-table-column>
      <el-table-column prop="status" label="状态">
        <template #default="{ row }">
          <el-tag :type="tagFilter(row.status)">
            {{ StatusType(row.status) }}
          </el-tag>
        </template>
      </el-table-column>
      <el-table-column prop="address" label="地址" />
      <el-table-column prop="lastLoginTime" label="日期">
        <template #default="{ row }">
          {{ dateTimeFilter(row.lastLoginTime) }}
        </template>
      </el-table-column>
      <el-table-column fixed="right" label="操作">
        <template #default="{ row }">
          <div>
            <el-button v-if="isValueExists('user-modifyuser')" link type="primary" size="small"
              @click.prevent="editInfo(row.userId)">编辑</el-button>
            <el-button v-if="isValueExists('user-removeuser')" link type="danger" size="small"
              @click="removeInfo(row.userId)">删除</el-button>
          </div>
          <div>
            <el-button v-if="isValueExists('user-getrolesbyuserid')" link type="success" size="small"
              @click="AssignRole(row.userId)">角色</el-button>
            <el-button v-if="isValueExists('user-getallmenubtnlist')" link type="warning" size="small"
              @click="AssignMenu(row.userId)">菜单</el-button>
            <el-button v-if="isValueExists('user-blockeduser')" link type="info" size="small"
              @click="blockedInfo(row.userId)">
              {{ row.status == -1 ? '解冻' : '冻结' }}
            </el-button>
          </div>
        </template>
      </el-table-column>
    </el-table>
    <!-- 分页 -->
    <div class="pagination">
      <el-pagination background layout="prev, pager, next, sizes" :total="totalCount" :hide-on-single-page="isHide"
        @size-change="handleSizeChange" @current-change="handleCurrentChange" />
    </div>
  </el-card>

  <!-- 用户编辑 -->
  <el-dialog v-model="dialogVisible" :title="modifyWindowTitle" width="30%" :before-close="handleClose">
    <el-form ref="ruleFormRef" :model="userInfo" :rules="rules" label-width="80px">
      <el-form-item label="姓名" prop="name">
        <el-input v-model="userInfo.name" />
      </el-form-item>
      <el-form-item label="性别" prop="sex">
        <el-radio-group v-model="userInfo.sex">
          <el-radio label="0">男</el-radio>
          <el-radio label="1">女</el-radio>
        </el-radio-group>
      </el-form-item>
      <el-form-item label="是否启用">
        <el-switch v-model="userInfo.status" />
      </el-form-item>
      <el-form-item label="头像">
        <el-upload class="avatar-uploader" action="https://localhost:7297/api/file" :show-file-list="false"
          :on-success="handleAvatarSuccess" :before-upload="beforeAvatarUpload">
          <img v-if="imagePath" :src="imagePath" class="avatar" />
          <el-icon v-else class="avatar-uploader-icon">
            <Plus />
          </el-icon>
        </el-upload>
      </el-form-item>
      <el-form-item label="密码" prop="password">
        <el-input show-password v-model="userInfo.password" />
      </el-form-item>
      <el-form-item label="确认密码" prop="confirmPassword">
        <el-input show-password v-model="userInfo.confirmPassword" />
      </el-form-item>
      <el-form-item label="电话" prop="phone">
        <el-input v-model="userInfo.phone" />
      </el-form-item>
      <el-form-item label="手机号" prop="mobile">
        <el-input v-model="userInfo.mobile" />
      </el-form-item>
      <el-form-item label="电子邮件" prop="email">
        <el-input v-model="userInfo.email" />
      </el-form-item>
      <el-form-item label="QQ">
        <el-input v-model="userInfo.qq" />
      </el-form-item>
      <el-form-item label="微信">
        <el-input v-model="userInfo.weChat" />
      </el-form-item>
      <el-form-item label="地址">
        <el-input type="textarea" v-model="userInfo.address" />
      </el-form-item>
    </el-form>
    <template #footer>
      <span class="dialog-footer">
        <el-button @click="closeWindow">取消</el-button>
        <el-button type="primary" @click="submit(ruleFormRef)">确定</el-button>
      </span>
    </template>
  </el-dialog>

  <!-- 角色 -->
  <el-dialog v-model="roleDialogVisible" title="角色分配" width="30%" :before-close="roleHandleClose">
    <div class="flex-container">
      <el-tooltip class="box-item" effect="dark" :content="item.roleName" placement="top" v-for="item in roleData.arr">
        <el-card class="box-card-setRole" :class="getSelectedClass(item)" @click.prevent="selectCurrentItem(item)"
          style="background-color: #fff;">
          <div style="color: #fff;">{{ ellipsisFilter(item.roleName) }}</div>
        </el-card>
      </el-tooltip>
    </div>
    <template #footer>
      <span class="dialog-footer">
        <el-button @click="closeRoleWindow">取消</el-button>
        <el-button type="primary" @click="submitRole()">确定</el-button>
      </span>
    </template>
  </el-dialog>

  <!-- 菜单 -->
  <el-dialog v-model="menuDialogVisible" title="菜单分配" width="30%" :before-close="menuHandleClose">
    <el-tree :data="menuTreeData.value" :props="{
      label: 'menuText',
      children: 'childMenus'
    }" show-checkbox node-key="id" empty-text="暂无数据" check-on-click-node="true" highlight-current="true"
      :expand-on-click-node="false" ref="menuMultipleTableRef" :default-checked-keys='selectedMenuArray.value'>
      <template #default="{ node, data }">
        <el-icon>
          <component :is="InitIcon(data.icon)"></component>
        </el-icon>
        <span>{{ node.label }}</span> <span style="color: red;">{{ node.isRoleMenu ? '【已在角色中分配】' : '' }}</span>
      </template>
    </el-tree>
    <template #footer>
      <span class="dialog-footer">
        <el-button @click="userMenuCancel">取消</el-button>
        <el-button type="primary" @click="userMenuSubmit">确定</el-button>
      </span>
    </template>

  </el-dialog>
</template>

<style scoped>
.avatar-uploader .avatar {
  width: 50px;
  height: 50px;
  display: block;
}

.avatar-uploader .el-upload {
  border: 1px dashed var(--el-border-color);
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  transition: var(--el-transition-duration-fast);
}

.avatar-uploader .el-upload:hover {
  border-color: var(--el-color-primary);
}

.el-icon.avatar-uploader-icon {
  font-size: 28px;
  color: #8c939d;
  width: 50px;
  height: 50px;
  text-align: center;
}

.flex-container {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
}

.box-card-setRole {
  height: 40px !important;
  width: 120px;
  margin: 2px;
  text-align: center;
  line-height: 0px;
  background-color: #409eff !important;
  cursor: pointer;
}

.roleSelected {
  background-color: #ff820e !important;
  cursor: pointer;
}
</style>

<script setup>
import { ref, onMounted, computed, reactive, markRaw, onBeforeMount } from 'vue'
import axios from '@/api'
import { defUrl } from '@/api/index'
import { ElMessage, ElMessageBox } from 'element-plus'
import { StatusType, InitIcon, currentMenuPermission } from "@/common";
import { useRouter } from "vue-router";
import {
  Search,
  Plus,
  Delete
} from "@element-plus/icons-vue";

const tableData = ref([]);
let totalCount = ref(0);
const isHide = ref(false);
const listQuery = reactive({
  pageIndex: 1,
  pageSize: 10,
  searchString: ''
});
const ruleFormRef = ref();
const isModify = ref(true);
const oldUser = ref({});
const imagePath = ref('')
const modifyWindowTitle = ref('新增');

const roleDialogVisible = ref(false);
const roleData = reactive({ arr: [] });
const selectedRoleData = reactive({ arr: [] });
const currentUserId = ref(0);
const roleSubmit = reactive({ roles: [], userId: 0 })
const selectedUserId = ref(0);
const menuDialogVisible = ref(false);
const menuTreeData = reactive([]);
const selectedMenuArray = reactive([]);
const menuMultipleTableRef = ref();
const btnArray = reactive([]);

//用户信息对象
let userInfo = reactive({
  name: '',
  password: '',
  confirmPassword: '',
  status: 0,
  phone: '',
  mobile: '',
  address: '',
  email: '',
  qq: '',
  weChat: '',
  sex: '0',
  avatarPath: ''
})

//#region 表单校验
//密码校验
const checkPassword = (rule, value, callback) => {
  if (isModify && userInfo.password == oldUser.value.password) {
    callback();
  }

  if (value === '') {
    callback(new Error('请再次输入密码'))
  } else if (value !== userInfo.password) {
    callback(new Error("两次输入的密码不一致"))
  } else {
    callback()
  }
}

//校验规则
const rules = reactive({
  name: [
    {
      required: true,
      message: '请输入姓名',
      trigger: 'blur'
    }
  ],
  password: [
    {
      required: true,
      message: '请输入密码',
      trigger: 'blur'
    }
  ],
  confirmPassword: [
    {
      validator: checkPassword,
      trigger: 'blur'
    }
  ],
  sex: [
    {
      required: true,
      message: '请选择性别',
      trigger: 'change'
    }
  ],
  mobile: [
    {
      required: true,
      message: '请输入手机号',
      trigger: 'blur',

    },
    {
      type: 'number',
      transform: (value) => parseInt(value),
      message: '手机号必须为数字',
      trigger: 'blur'
    }
  ],
  phone: [
    {
      type: 'number',
      transform: (value) => parseInt(value),
      message: '电话必须为数字',
      trigger: 'blur'
    }
  ],
  email: [
    {
      type: 'email',
      message: '邮箱格式不正确',
      trigger: 'blur'
    }
  ],
  qq: [
    {
      type: 'number',
      message: 'QQ号必须为至少5位的纯数字',
      min: 5,
      transform: (value) => Number(value),
      trigger: 'blur'
    }
  ]
})
//#endregion

//页面加载完成后的钩子函数
onBeforeMount(() => {
  var menuId = useRouter().currentRoute.value.meta.id;
  btnArray.value = currentMenuPermission(menuId);
})

onMounted(() => {
  keydownEvent();

  userQuery();
})

const keydownEvent = () => {
  document.onkeydown = (e) => {
    if (e.defaultPrevented) {
      return;
    }

    const body = document.getElementsByTagName('body')[0];
    if (e.key === 'Enter') {
      userQuery();
    }
  }
}

//查询
async function userQuery() {
  //向后端发送请求，获取用户数据
  let url = `User/${listQuery.pageIndex}/${listQuery.pageSize}/${listQuery.searchString}`;
  let { data } = await axios.get(url);

  let { data: d, success, message } = data;

  if (success) {
    // 表格数据
    tableData.value = d.dataList;
    totalCount.value = d.recordCount;
  } else {
    ElMessage({
      type: "warning",
      message: message
    });
  }
}

//#region 文本格式化
const sexFilter = computed(() => item => {
  switch (item) {
    case 0:
      return '男';
    case 1:
      return '女';
    default:
      return item;
  }
})

const statusFilter = computed(() => item => {
  switch (item) {
    case 0:
      return '未激活';
    case 1:
      return '正常';
    case -1:
      return '冻结';
    case -2:
      return '已删除';
    default:
      return '异常';
  }
})

const tagFilter = computed(() => item => {
  switch (item) {
    case 1:
      return 'success';
    case 0:
      return 'info'
    case -1:
      return 'warning'
    default:
      return 'danger'
  }
})

const dateTimeFilter = computed(() => item => {
  return item.toString().replace('T', ' ');
})

const imgUrlFilter = computed(() => item => {
  return `${defUrl}${item}`
})

const ellipsisFilter = computed(() => item => {
  if (!item) {
    return '';
  }

  if (item.length > 5) {
    let str = `${item.slice(0, 5)}...`;

    return str;
  }

  return item;
})
//#endregion

const getSelectedClass = computed(() => item => {
  for (var index in selectedRoleData.arr) {
    var name = selectedRoleData.arr[index];

    if (name.roleName === item.roleName) {
      return 'roleSelected';
    }
  }
})

const dialogVisible = ref(false)

//窗体关闭
const handleClose = (done) => {
  userInfo = reactive({
    name: '',
    password: '',
    confirmPassword: '',
    status: 0,
    phone: '',
    mobile: '',
    address: '',
    email: '',
    qq: '',
    weChat: '',
    sex: '0',
    avatarPath: ''
  });

  imagePath.value = "";

  done();
}

//角色窗体关闭
const roleHandleClose = (done) => {
  done();
}

//切换页大小
const handleSizeChange = (val) => {
  listQuery.pageSize = val;
  userQuery();
}

//翻页
const handleCurrentChange = (val) => {
  listQuery.pageIndex = val;
  userQuery();
}

//新增
const addInfo = () => {
  isModify.value = false;
  modifyWindowTitle.value = '新增'

  if (ruleFormRef.value !== undefined) {
    ruleFormRef.value.resetFields();
  }

  imagePath.value = "";

  dialogVisible.value = true
}

//删除
const removeInfo = async (id) => {
  ElMessageBox.confirm('是否删除？', '提醒', {
    type: 'warning',
    icon: markRaw(Delete)
  })
    .then(async () => {
      let { data } = await axios.delete(`/user/${id}`);
      let { success, message } = data;

      if (success) {
        ElMessage({
          type: "success",
          message: "删除成功"
        });

        await userQuery();
      } else {
        ElMessage({
          type: "warning",
          message: message
        });
      }
    })
    .catch(() => {
      ElMessage({
        type: "warning",
        message: '操作已取消'
      });
    })
}

//编辑
const editInfo = async (id) => {
  isModify.value = true;
  modifyWindowTitle.value = '编辑';

  if (ruleFormRef.value !== undefined) {
    ruleFormRef.value.resetFields();
  }

  let { data } = await axios.get(`User/${id}`);
  console.log(data);

  let { data: d, success, message } = data;
  if (!success) {
    ElMessage({
      type: 'error',
      message: message
    });

    return;
  }

  oldUser.value = d;

  userInfo.address = d.address;
  userInfo.email = d.email;
  userInfo.mobile = parseInt(d.mobile);
  userInfo.name = d.name;
  userInfo.password = d.password;
  userInfo.phone = d.phone;
  userInfo.qq = d.qq;
  userInfo.sex = d.sex.toString();
  userInfo.status = d.status == 1;
  userInfo.weChat = d.weChat;
  userInfo.userId = d.userId;
  userInfo.avatarPath = d.avatarPath;
  userInfo.lastLoginTime = d.lastLoginTime;
  imagePath.value = d.avatarPath ? `${defUrl}${d.avatarPath}` : "";

  console.log(userInfo);

  dialogVisible.value = true;
}

//提交
const submit = async (formEl) => {
  if (!formEl) return
  //校验
  await formEl.validate(async (valid, fields) => {
    if (valid) {
      userInfo.status = userInfo.status ? 1 : 0
      userInfo.mobile = userInfo.mobile.toString();

      if (isModify.value) {
        let { data } = await axios.put('user', userInfo);
        let { data: d, success, message } = data;

        if (!success) {
          ElMessage({
            type: 'error',
            message: message
          });

          return;
        }
      } else {
        let { data } = await axios.post('user', userInfo);
        let { data: d, success, message } = data;

        if (!success) {
          ElMessage({
            type: 'error',
            message: message
          });

          return;
        }
      }

      ElMessage({
        type: 'success',
        message: '保存成功'
      });

      dialogVisible.value = false;

      imagePath.value = "";

      await userQuery();
    } else {
      ElMessage({
        type: 'warning',
        message: '验证失败，请正确输入信息后再提交'
      });
    }
  });
}

//冻结/解冻
const blockedInfo = async (id) => {
  ElMessageBox.confirm('是否冻结/解冻？', '提醒', {
    type: 'warning',
    icon: markRaw(Delete)
  })
    .then(async () => {
      let { data } = await axios.put(`/user/blocked/${id}`);
      let { success, message } = data;

      if (success) {
        ElMessage({
          type: "success",
          message: "冻结/解冻成功"
        });

        await userQuery();
      } else {
        ElMessage({
          type: "warning",
          message: message
        });
      }
    })
    .catch(() => {
      ElMessage({
        type: "warning",
        message: '操作已取消'
      });
    })
}

//头像上传之前
const beforeAvatarUpload = async (rawFile) => {
  if (rawFile.type !== 'image/jpeg') {
    ElMessage.error('只能上传【image/jpeg】格式的文件')
    return false
  } else if (rawFile.size / 1024 / 1024 > 2) {
    ElMessage.error('只能上传2M以内的文件')
    return false
  }
  return true
}

//头像文件上传成功后
const handleAvatarSuccess = async (response, uploadFile) => {
  if (response.success) {
    userInfo.avatarPath = response.data;

    imagePath.value = `${defUrl}${response.data}`;

    ElMessage({
      type: 'success',
      message: '上传成功'
    });
  } else {
    ElMessage({
      type: 'warning',
      message: response.message
    });
  }
}

//窗体关闭
const closeWindow = () => {
  dialogVisible.value = false;

  userInfo = reactive({
    userId: 0,
    name: '',
    password: '',
    confirmPassword: '',
    status: 0,
    phone: '',
    mobile: '',
    address: '',
    email: '',
    qq: '',
    weChat: '',
    sex: '0',
    avatarPath: ''
  });

  imagePath.value = "";
}

//分配角色
const AssignRole = async (id) => {
  roleDialogVisible.value = true;

  currentUserId.value = parseInt(id);

  let url = `Role`;
  let { data } = await axios.get(url);
  console.log(data);

  let { data: d, success, message } = data;

  if (success) {
    // 表格数据
    roleData.arr = d;
  } else {
    ElMessage({
      type: 'warning',
      message: message
    });
  }

  let { data: rData } = await axios.get(`User/Role/${id}`);
  console.log(rData);

  let { data: v, success: s, message: m } = rData
  console.log(v);

  if (!s) {
    ElMessage({
      type: 'warning',
      message: m
    });

    return;
  }

  selectedRoleData.arr = v;
}

//勾选角色
const selectCurrentItem = async (item) => {
  if (selectedRoleData.arr.filter(a => a.roleId === item.roleId).length > 0) {
    //Vue3中，reactive数组无法使用indexOf获得索引，需使用findIndex
    let i = selectedRoleData.arr.findIndex((value) => value.roleId === item.roleId);

    selectedRoleData.arr.splice(i, 1);
  } else {
    selectedRoleData.arr.push(item);
  }
}

//窗体关闭
const closeRoleWindow = () => {
  roleDialogVisible.value = false;
}

//提交选中角色
const submitRole = async () => {
  roleDialogVisible.value = false;

  roleSubmit.roles = selectedRoleData.arr;
  roleSubmit.userId = currentUserId.value;
  let { data } = await axios.put('UserRole', roleSubmit);

  let { data: d, success, message } = data
  console.log(d);

  if (!success) {
    ElMessage({
      type: 'warning',
      message: message
    });

    return;
  }

  ElMessage({
    type: 'success',
    message: '设置成功'
  });
}

//分配菜单
const AssignMenu = async (userId) => {
  selectedUserId.value = userId;

  let { data } = await axios.get(`User/Menu/${userId}`);
  let { data: d, success, message, otherSource } = data;

  if (!success) {
    ElMessage({
      type: 'warning',
      message: message
    });

    return;
  }

  menuTreeData.value = d;
  selectedMenuArray.value = otherSource;

  menuDialogVisible.value = true;
}

//菜单窗体关闭
const menuHandleClose = (done) => {
  done();
}

//取消菜单选择
const userMenuCancel = async () => {
  menuDialogVisible.value = false;
}

//提交菜单分配
const userMenuSubmit = async () => {
  let selectedArray = menuMultipleTableRef.value.getCheckedNodes();
  let halfSelectedArray = menuMultipleTableRef.value.getHalfCheckedNodes();

  let arr = selectedArray.concat(halfSelectedArray);
  let fullSelected = arr.filter(n => n.disabled == false);

  if (fullSelected.length === 0) {
    ElMessage({
      type: 'warning',
      message: '请先勾选菜单'
    });

    return;
  }

  let { data } = await axios.post(`User/SetUserMenu`, { userId: selectedUserId.value, menus: fullSelected });
  let { success, message } = data;

  if (!success) {
    ElMessage({
      type: 'warning',
      message: message
    });

    return;
  }

  ElMessage({
    type: 'success',
    message: '设置成功'
  });

  menuDialogVisible.value = false
}

const isValueExists = (item) => {
  var arr = btnArray.value.filter(b => b.btnValue === item);

  return arr.length > 0;
}
</script>